/*
 * Copyright (c) Huawei Technologies Co., Ltd. 2017-2023. All rights reserved.
 * Description: ai stats log manager class
 */

#include "infra/om/stats/ai_stats_log_manager.h"

#include <fstream>
#include <algorithm> // sort
#include <thread>
#include <algorithm>
#include <iostream>
#include <string>

#include "infra/om/stats/ai_stats_log_common.h"
#include "infra/om/stats/ai_stats_log_utils.h"
#include "infra/om/stats/ai_stats_time.h"

#include "ai_stats_log_file_writer.h"

namespace {
    const int MAX_BUFFER_SIZE = 1000;
}
namespace hiai {

AiStatsLogWriter::AiStatsLogWriter()
{
    AiStatsLogFileWriter::GetInstance();
}

void AiStatsLogWriter::Write(AiStatsData& item, AiStatsEngineType type)
{
    std::lock_guard<std::mutex> lk(logBufferLock_);

    auto it = logBuffer_.find(item.callPkg);
    if (it != logBuffer_.end()) {
        const auto& iter = it->second.find(item.interfaceName);
        if (iter != it->second.end()) {
            logBuffer_[item.callPkg][item.interfaceName] = AiStatsLogUtils::AddAiStatsData(iter->second, item);
        } else {
            logBuffer_[item.callPkg][item.interfaceName] = item;
        }
    } else {
        std::map<std::string, AiStatsData> data;
        data[item.interfaceName] = item;
        logBuffer_[item.callPkg] = data;
    }

    logBufferSize_++;
    // max logBuffer_ size is 1000, then write to file
    if (logBufferSize_ >= MAX_BUFFER_SIZE) {
        AiStatsLogFileWriter* statsLogWriter = AiStatsLogFileWriter::GetInstance();
        statsLogWriter->CopyBuffer(this->logBuffer_, type);
        this->logBuffer_.clear();
        logBufferSize_ = 0;
    }
}

void AiStatsLogWriter::WriteToFile(AiStatsEngineType type)
{
    std::lock_guard<std::mutex> lk(logBufferLock_);
    if (this->logBuffer_.empty()) {
        return;
    }
    AiStatsLogFileWriter* statsLogWriter = AiStatsLogFileWriter::GetInstance();
    statsLogWriter->CopyBuffer(this->logBuffer_, type);
    this->logBuffer_.clear();
    logBufferSize_ = 0;
}

void AiStatsLogWriter::WriteToFileSync(AiStatsEngineType type)
{
    std::lock_guard<std::mutex> lk(logBufferLock_);
    if (this->logBuffer_.empty()) {
        return;
    }
    AiStatsLogFileWriter* statsLogWriter = AiStatsLogFileWriter::GetInstance();
    statsLogWriter->WriteToFile(type, this->logBuffer_);
    this->logBuffer_.clear();
    logBufferSize_ = 0;
}
/*
 * 该接口仅在打点定时器超时时被调用。
 * 1. 负责删除超出日志保留天数上限的日志
 * 2. 如果日志时间在当前时间的未来某天，则删除该日志。
 * 比如：第一次存储的日志时间为20180715，当系统时间背修改后，系统当前时间变成了20170815，则20180715的日志需要删除
 */
void AiStatsLogWriter::DeleteLogFile(AiStatsEngineType type)
{
    std::lock_guard<std::mutex> lk(deleteFileLock_);
    // 1. 获取MM所有日志的名字。该名字是绝对路径全名
    std::string dir(AiStatsLogCfgUtils::GetLogPathWithType(type));
    std::vector<std::string> files = AiStatsLogUtils::GetFilesName(dir);
    std::string today = AiStatsTime::Today();
    std::string todayLogName = dir.append(today).append(".log");

    // delete future_log_file and empty_file
    files.erase(std::remove_if(files.begin(), files.end(),
        [todayLogName](std::string filename) {
            if (filename > todayLogName || AiStatsLogCfgUtils::GetFileSize(filename) == 0) {
                STATS_LOGW("AiStatsLogWriter::DeleteLogFile: [%s] is future log or empty_file",
                    filename.c_str());
                AiStatsLogUtils::DeleteStatsLog(filename);
                return true;
            }
            return false;
        }),
        files.cend());

    int reserveDays = AiStatsLogCfgUtils::GetStatsLogReserveDays(type);
    if (reserveDays == -1) {
        STATS_LOGE("AiStatsLogWriter::DeleteLogFile:  not get statistics log retention days,not need to delete.");
        std::for_each(files.begin(), files.end(), AiStatsLogUtils::DeleteStatsLog);
        return;
    }
    // 2. 目前文件数量未超过配置，则暂不删除
    if (static_cast<int>(files.size()) <= reserveDays) {
        STATS_LOGD("AiStatsLogWriter::DeleteLogFile: current log counter is[%d],cfg is[%d],not need to delete.",
            static_cast<int>(files.size()), reserveDays);
        return;
    }
    // 文件名按照升序排列,按照从过去到现在的时间排序
    sort(files.begin(), files.end());
    // 3. 多余的日志删掉
    int deleteLogNumbers = static_cast<int>(files.size()) - reserveDays;

    std::string tmp;
    for (int i = 0; i < deleteLogNumbers; ++i) {
        tmp = files[i];
        AiStatsLogUtils::DeleteStatsLog(tmp);
    }
}

AiMMStatsLogWriter* AiMMStatsLogWriter::GetInstance()
{
    static AiMMStatsLogWriter instance;
    return &instance;
}

void AiMMStatsLogWriter::Write(AiStatsData& item)
{
    this->AddVersion(item);

    // add {} for waitProcessNameLock_
    {
        // 同一个进程ID保存没有进程名称的数据限制5条,保存没有进程名称的的进程数据限制5个进程
        const size_t limitMaxSize = 5;
        std::lock_guard<std::mutex> lk(waitProcessNameLock_);
        if (item.processName.size() == 0) {
            if (waitProcessName_.size() > limitMaxSize) {
                waitProcessName_.clear();
            }
            if (waitProcessName_.find(item.callPkg) != waitProcessName_.end()) {
                if (waitProcessName_[item.callPkg].size() > limitMaxSize) {
                    waitProcessName_[item.callPkg].clear();
                }
                waitProcessName_[item.callPkg].push_back(item);
            } else {
                std::vector<AiStatsData> buffer;
                buffer.push_back(item);
                waitProcessName_[item.callPkg] = buffer;
            }
            return;
        }

        auto iter = waitProcessName_.find(item.callPkg);
        if (iter != waitProcessName_.end()) {
            for (auto it : iter->second) {
                it.processName = item.processName;
                AiStatsLogWriter::Write(it, AI_STATS_HIAI_MNGR);
            }
        }
        waitProcessName_.erase(item.callPkg);
    }
    AiStatsLogWriter::Write(item, AI_STATS_HIAI_MNGR);
}
// 该接口在定时器超时时被调用
void AiMMStatsLogWriter::WriteToFile()
{
    AiStatsLogWriter::WriteToFile(AI_STATS_HIAI_MNGR);
}

void AiMMStatsLogWriter::DeleteLogFile()
{
    AiStatsLogWriter::DeleteLogFile(AI_STATS_HIAI_MNGR);
}

void AiMMStatsLogWriter::AddVersion(AiStatsData& item)
{
    if (ddkVersion_.empty()) {
        ddkVersion_ = AiStatsLogUtils::GetAiDDKVersion();
        if (ddkVersion_.empty()) {
            ddkVersion_ = "default_version";
        }
    }

    if (item.ddkVersion.size() == 0) {
        item.ddkVersion = ddkVersion_;
    }
}

AiHiAiEngineStatsLogWriter* AiHiAiEngineStatsLogWriter::GetInstance()
{
    static AiHiAiEngineStatsLogWriter instance;
    return &instance;
}

void AiHiAiEngineStatsLogWriter::Write(AiStatsData& item)
{
    this->AddVersion(item);

    AiStatsLogWriter::Write(item, AI_STATS_HIAI_ENGINE);
}
// 该接口在定时器超时时被调用
void AiHiAiEngineStatsLogWriter::WriteToFile()
{
    AiStatsLogWriter::WriteToFile(AI_STATS_HIAI_ENGINE);
}

void AiHiAiEngineStatsLogWriter::DeleteLogFile()
{
    AiStatsLogWriter::DeleteLogFile(AI_STATS_HIAI_ENGINE);
}

void AiHiAiEngineStatsLogWriter::AddVersion(AiStatsData& item)
{
    // if the version has't been added,add the default version
    if (item.ddkVersion.size() == 0) {
        item.ddkVersion = "1.0.0";
    }
}

AiANNStatsLogWriter* AiANNStatsLogWriter::GetInstance()
{
    static AiANNStatsLogWriter instance;
    return &instance;
}

void AiANNStatsLogWriter::Write(AiStatsData& item)
{
    this->AddVersion(item);
    AiStatsLogWriter::Write(item, AI_STATS_ANN);
}
// 该接口在定时器超时时被调用
void AiANNStatsLogWriter::WriteToFile()
{
    AiStatsLogWriter::WriteToFile(AI_STATS_ANN);
}

void AiANNStatsLogWriter::DeleteLogFile()
{
    AiStatsLogWriter::DeleteLogFile(AI_STATS_ANN);
}

void AiANNStatsLogWriter::AddVersion(AiStatsData& item)
{
    // if the version has't been added,add the default version
    if (ddkVersion_.empty()) {
        ddkVersion_ = AiStatsLogUtils::GetAiDDKVersion();
        if (ddkVersion_.empty()) {
            ddkVersion_ = "default_version";
        }
    }

    if (item.ddkVersion.size() == 0) {
        item.ddkVersion = ddkVersion_;
    }
}

AiHiAiHCSStatsLogWriter* AiHiAiHCSStatsLogWriter::GetInstance()
{
    static AiHiAiHCSStatsLogWriter instance;
    return &instance;
}

void AiHiAiHCSStatsLogWriter::Write(AiStatsData& item)
{
    this->AddVersion(item);
    AiStatsLogWriter::Write(item, AI_STATS_HIAI_HCS);
}
// 该接口在定时器超时时被调用
void AiHiAiHCSStatsLogWriter::WriteToFile()
{
    AiStatsLogWriter::WriteToFile(AI_STATS_HIAI_HCS);
}

void AiHiAiHCSStatsLogWriter::DeleteLogFile()
{
    AiStatsLogWriter::DeleteLogFile(AI_STATS_HIAI_HCS);
}

void AiHiAiHCSStatsLogWriter::AddVersion(AiStatsData& item)
{
    // if the version has't been added,add the default version
    if (item.ddkVersion.size() == 0) {
        item.ddkVersion = "000.000.000"; // TO DO
    }
}

AiHiAiDDKStatsLogWriter* AiHiAiDDKStatsLogWriter::GetInstance()
{
    static AiHiAiDDKStatsLogWriter instance;
    return &instance;
}

void AiHiAiDDKStatsLogWriter::Write(AiStatsData& item)
{
    this->AddVersion(item);
    AiStatsLogWriter::Write(item, AI_STATS_HIAI_DDK);
}

void AiHiAiDDKStatsLogWriter::WriteToFile()
{
    AiStatsLogWriter::WriteToFile(AI_STATS_HIAI_DDK);
}

void AiHiAiDDKStatsLogWriter::DeleteLogFile()
{
    AiStatsLogWriter::DeleteLogFile(AI_STATS_HIAI_DDK);
}

void AiHiAiDDKStatsLogWriter::AddVersion(AiStatsData& item)
{
    if (ddkVersion_.empty()) {
        ddkVersion_ = AiStatsLogUtils::GetAiDDKVersion();
        if (ddkVersion_.empty()) {
            ddkVersion_ = "default_version";
        }
    }

    if (item.ddkVersion.size() == 0) {
        item.ddkVersion = ddkVersion_;
    }
}
} // end namespace ai
